package {
import com.flashflexpro.tanksinbattle.loader.LoadModuleEvent;
import com.flashflexpro.tanksinbattle.scene.AModule;
import com.flashflexpro.tanksinbattle.scene.ModuleDependencyResolver;
import com.flashflexpro.tanksinbattle.scene.dto.BitDependencyDto;
import com.flashflexpro.tanksinbattle.scene.dto.Dto;
import com.flashflexpro.tanksinbattle.scene.dto.DependencyDto;

import com.flashflexpro.tanksinbattle.scene.dto.FutureModuleInstDto;
import com.flashflexpro.tanksinbattle.scene.dto.UrlDependencyDto;

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.NetConnection;
import flash.net.Responder;
import flash.net.registerClassAlias;
import flash.system.ApplicationDomain;
import flash.utils.describeType;

[SWF(width="800", height="555", backgroundColor="#BBBBBB", frameRate="32")]
public class LoaderMain extends Sprite {

    private var _nextModule:FutureModuleInstDto;
    private var _passingArg:Dto;

    public function LoaderMain() {
        stage.align = StageAlign.TOP_LEFT;
        stage.scaleMode = StageScaleMode.NO_SCALE;
        registerClassAlias("com.flashflexpro.tanksinbattle.scene.dto.DependencyDto", DependencyDto);
        registerClassAlias("com.flashflexpro.tanksinbattle.scene.dto.UrlDependencyDto", UrlDependencyDto);
        registerClassAlias("com.flashflexpro.tanksinbattle.scene.dto.BitDependencyDto", BitDependencyDto);
        registerClassAlias("com.flashflexpro.tanksinbattle.scene.dto.FutureModuleInstDto", FutureModuleInstDto);

        var amf:NetConnection = new NetConnection();
        amf.connect("http://localhost:8080/messagebroker/amf", "my-amf");
        amf.call("init-facade.getInitScene", new Responder(onResult, onError));
    }

    private function onError(o:*):void {
        //todo:handle this
        trace( "LoaderMain.onError" + o);
    }

    private function onResult(result:FutureModuleInstDto):void {
        stage.addEventListener(LoadModuleEvent.LOAD_NEXT_MODULE, onLoadNextModule);

        _nextModule = result;
        if( _nextModule.main == null ){
            throw new Error( "Future Module's main class can't be null!" );
        }

        var resolver:ModuleDependencyResolver = new ModuleDependencyResolver();
        resolver.addEventListener(Event.COMPLETE, onFutureModuleReady);
        resolver.resolve( _nextModule.dependencies );
    }

    private function onLoadNextModule(event:LoadModuleEvent):void {
        _nextModule = event.nextModule;
        _passingArg = event.throughDoor;
        var resolver:ModuleDependencyResolver = new ModuleDependencyResolver();
        resolver.addEventListener( IOErrorEvent.IO_ERROR, onFutureModuleIoError );
        resolver.addEventListener(Event.COMPLETE, onFutureModuleReady);
        resolver.resolve( _nextModule.dependencies );
    }

    private function onFutureModuleIoError(event:IOErrorEvent):void {
        throw new Error( event );
    }

    private var _loadingModule:AModule;

    private function onFutureModuleReady(event:Event):void {
        ( event.target as EventDispatcher ).removeEventListener(Event.COMPLETE, onFutureModuleReady);

        var entry:Class = ApplicationDomain.currentDomain.getDefinition(_nextModule.main) as Class;
        if (entry == null) {
            throw new Error("Entry Class is null!");
        }
        _loadingModule = new entry( _nextModule.dto!=null?_nextModule.dto.readObject():null ) as AModule;
        if (_loadingModule == null) {
            var x:XML = describeType(entry);
            throw new Error("Not AModule:" + x);
        }
        _loadingModule.addEventListener(LoadModuleEvent.MODULE_READY, onModuleReady);
        _loadingModule.start(_passingArg);
    }

    private function onModuleReady(event:Event):void {
        _loadingModule.removeEventListener(LoadModuleEvent.MODULE_READY, onModuleReady);

        //this has to stay to keep stage ref
        while (stage.numChildren > 1) {
            var child:DisplayObject = stage.getChildAt(0);
            var m:AModule = child as AModule;
            if (m != null) {
                m.destroy();
            }
            if (child != this) {
                stage.removeChild(child);
            }
        }
        stage.addChildAt(_loadingModule as DisplayObject, 0 );
    }


}
}